<?php
abstract class Dmf_Application_Widget
{
    /**
     * The tagname of the widget
     * 
     * @var string
     */
    private $_tagname;
    
    /**
     * All widget attributes
     * 
     * @var array
     */
    private $_attributes = array();
    
    /**
     * The view resource
     * 
     * @var Dmf_View
     */
    protected $_resource;
    
    /**
     * Data giving to the widget
     * 
     * @var mixed
     */
    protected $_data;
    
    /**
     * All dependency files
     * 
     * @var array
     */
    protected $_dependencies = array();
    
    /**
     * All dependency files that already have been included
     * 
     * @var array 
     */
    public static $dependencies = array();
    
    /**
     * All configuration settings
     * 
     * @var Dmf_Stdclass
     */
    private $_config;
    
    /**
     * Parse the widget from a view or form instance.
     *
     * @param string $tagname
     * @param array $attributes
     * @param mixed $data
     * @return string 
     */
    public static function parse( $tagname, $attributes, $data )
    {
        $class = $tagname . 'Widget';
        $widget = new $class( $tagname );
        
        $widget->setAttributes( $attributes );
        $widget->setData( $data );
        
        return $widget->render();
    }
    
    /**
     * Constructor
     * 
     * @param string $tagname 
     */
    public function __construct( $tagname )
    {
        $this->_config = Dmf_Application::getInstance()->getConfig()->asObject();
        $this->_controller = Dmf_Application_Controller::getInstance();
        $this->_tagname = $tagname;
        $this->_readXmlFile( 'widgets/elements.xml' );
    }
    
    /**
     * Set all attributes
     * 
     * @param type $attributes 
     */
    public function setAttributes( $attributes )
    {
        $this->_attributes = array_merge( $this->_attributes, $this->_getAttributesFromString( $attributes ) );
    }
    
    /**
     * Set the data
     * 
     * @param Dmf_View $data 
     */
    public function setData( $data )
    {
        $this->_data = $data;
        
        if ( $data instanceof Dmf_View )
        {
            $index = $this->getAttr( 'data' );
            
            $this->_data = $data->$index;
        }
    }
    
    /**
     * Get all data
     * 
     * @return mixed 
     */
    public function getData()
    {
        if ( is_array( $this->_data ) )
        {
            return $this->_data;
        }
        
        $index = $this->getAttr( 'data' );
        
        return $this->_data->$index;
    }
    
    /**
     * Get all dependencies as array
     * 
     * @return array 
     */
    private function _getDependencies()
    {
        $dependencies = array();
        
        foreach( $this->_dependencies as $dependency )
        {
            $dependencies[] = array( 
                    'href' => $this->_config->application->public_path . str_replace( '%theme%', ( ( $this->getAttr( 'theme' ) != null ) ? $this->getAttr( 'theme' ) : 'default' ), (string)$dependency['href'] ), 
                    'type' => (string)$dependency['type'],
                    'when' => (string)$dependency['when']
                );
        }
        
        return $dependencies;
    }
    
    /**
     * Assign variable to Widget-view
     * 
     * @param string $index
     * @param mixed $value 
     */
    public function assign( $index, $value )
    {
        $this->_resource->assign( $index, $value );
    }
    
    /**
     * Get all attributes from HTML-string
     * 
     * @param string $string
     * @return array
     */
    private function _getAttributesFromString( $string )
    {
        if ( is_array( $string ) )
        {
            return $string;
        }
        
        $attributes = array();
        
        foreach( explode( ' ', $string ) as $attrib )
        {
            preg_match( '/([^\=]*)\=["|\']([^"\']*)["|\']/', $attrib, $match );
            
            if ( ! isset( $match['1'] ) || ! isset( $match['2'] ) )
            {
                continue;
            }
            
            $attributes[ $match['1'] ] = $match['2'];
        }
        
        return $attributes;
    }
    
    /**
     * Get attribute
     * 
     * @param string $index
     * @return mixed
     */
    public function getAttr( $index )
    {
        return isset( $this->_attributes[ $index ] ) ? $this->_attributes[ $index ] : null;
    }
    
    /**
     * Set attribute
     * 
     * @param string $index
     * @param mixed $valued
    * @return mixed
     */
    public function setAttr( $index, $value = null )
    {
        $this->_attributes[ $index ] = $value;
    }
    
    /**
     * Parse the widget 
     */
    abstract function parseWidget();
    
    /**
     * Read xml data and parse it
     * 
     * @param string $file 
     */
    private function _readXmlFile( $file )
    {
        $xml = new SimpleXMLElement( file_get_contents( $file ) );
        
        foreach( $xml->element as $element )
        {
            if ( (string)$element['name'] != $this->_tagname )
            {
                continue;
            }
            
            foreach( $element->attributes->attribute as $attribute )
            {
                $this->_attributes[ (string)$attribute['name'] ] = (string)$attribute['default_value'];
            }
            
            foreach( $element->dependencies->dependency as $dependency )
            {
                $this->_dependencies[] = $dependency;
            }
        }
    }
    
    /**
     * Render the full widget
     */
    public final function render()
    {
        $headText = '';
        
        foreach( $this->_getDependencies() as $dependency )
        {
            if ( in_array( $dependency['href'], self::$dependencies ) )
            {
                continue;
            }
            
            if ( strstr( $dependency['when'], ':' ) )
            {
                list( $key, $val ) = explode( ':', $dependency['when'] );
                
                if ( $this->getAttr( $key ) != $val )
                {
                    continue;
                }
            }
            
            self::$dependencies[] = $dependency['href'];
            
            switch( $dependency['type'] )
            {
                case 'css':
                    $headText .= '<link rel="stylesheet" type="text/css" href="' . $dependency['href'] . '" />' . "\n";
                    break;
                case 'js':
                case 'javascript':
                    $headText .= '<script type="text/javascript" src="' . $dependency['href'] . '"></script>' . "\n";
                    break;
            }
        }
        
        if ( isset( $this->_attributes['value'] ) && is_array( $this->_attributes['value'] ) )
        {
            $this->_attributes['value'] = implode( '|', $this->_attributes['value'] );
        }
        
        $this->_resource = new Dmf_Resource( 'widgets/views/' . $this->_tagname . '.phtml' );
        $this->_resource->replace( '{Dependencies}', '<div class="dmf-dependencies">' . "\n" . $headText . "\n" . '</div>' );
        $this->parseWidget();
        
        unset($this->_attributes['data']);
        
        $this->_resource->assign( 'data_attributes', $this->_attributes );
        
        $this->_resource->render();
    }
}